package models

import (
	"encoding/xml"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
)

type Subscriber struct {
	Id          string
	Accountcode string
	Password    string
	Name        string
	Right       string
}

func GetAllSubscribers() []Subscriber {
	var v visitor

	filepath.Walk(getUserConfDir(),
		func(path string, f os.FileInfo, err error) error {
			v.visit(path, f, err)
			return nil
		})
	return v.subs
}

func IsSubscriberExist(accountcode string) bool {
	var path string = getUserConfDir() + "/" + accountcode + ".xml"
	if _, err := os.Stat(path); err == nil {
		return true
	}
	return false
}

func AddSubscriber(accountcode string, password string) error {
	var path string = getUserConfDir() + "/" + accountcode + ".xml"
	var include Include
	include.User.Id = accountcode

	include.User.Params = make([]Param, 0)
	include.User.Params = append(include.User.Params,
		Param{"password", password})
	include.User.Params = append(include.User.Params,
		Param{"vm-password", accountcode})

	include.User.Variables = make([]Variable, 0)
	include.User.Variables = append(include.User.Variables,
		Variable{"toll_allow", "domestic,international,local"})
	include.User.Variables = append(include.User.Variables,
		Variable{"accountcode", accountcode})
	include.User.Variables = append(include.User.Variables,
		Variable{"user_context", "cykj"})
	include.User.Variables = append(include.User.Variables,
		Variable{"effective_caller_id_name", "Extension " + accountcode})
	include.User.Variables = append(include.User.Variables,
		Variable{"effective_caller_id_number", accountcode})
	include.User.Variables = append(include.User.Variables,
		Variable{"outbound_caller_id_name", "$${outbound_caller_name}"})
	include.User.Variables = append(include.User.Variables,
		Variable{"outbound_caller_id_number", "$${outbound_caller_id}"})
	include.User.Variables = append(include.User.Variables,
		Variable{"callgroup", "techsupport"})

	data, err := xml.MarshalIndent(&include, "", "  ")
	if err != nil {
		return err
	}

	var f *os.File
	f, err = os.Create(path)
	if err != nil {
		fmt.Println(err.Error())
		return err
	}
	io.WriteString(f, string(data))
	f.Close()

	return nil
}

func DelSubscriber(accountcode string) error {
	var path string = getUserConfDir() + "/" + accountcode + ".xml"

	err := os.Remove(path)
	if err != nil {
		fmt.Println(err.Error())
	}

	return nil
}

func getUserConfDir() string {
	return filepath.Join(getFSConfDir(), "directory/default")
}

type visitor struct {
	subs []Subscriber
}

func (v *visitor) visit(path string, f os.FileInfo, err error) error {
	if f.IsDir() {
		return nil
	}
	if isUserConfFile(path) {
		var sub *Subscriber
		sub = getSubFromFile(path)
		if sub != nil {
			v.subs = append(v.subs, *sub)
		}

	}

	return nil
}

func isUserConfFile(path string) bool {
	if path != "" {
		isOK, _ := regexp.MatchString("[\\d]+.xml", path)
		if isOK {
			return true
		}
	}
	return false
}

func getSubFromFile(path string) *Subscriber {
	content, err := ioutil.ReadFile(path)
	if err != nil {
		return nil
	}

	include := Include{}
	err = xml.Unmarshal(content, &include)
	if err != nil {
		return nil
	}

	u := include.User
	var sub Subscriber
	sub.Id = u.Id
	for _, param := range u.Params {
		if param.Name == "password" {
			sub.Password = param.Value
		}
	}

	for _, variable := range u.Variables {
		if variable.Name == "accountcode" {
			sub.Accountcode = variable.Value
		}
		if variable.Name == "effective_caller_id_name" {
			sub.Name = variable.Value
		}
		if variable.Name == "toll_allow" {
			sub.Right = variable.Value
		}
	}

	return &sub
}

type Include struct {
	XMLName xml.Name `xml:"include"`
	User    User     `xml:"user"`
}

type User struct {
	Id        string     `xml:"id,attr"`
	Params    []Param    `xml:"params>param"`
	Variables []Variable `xml:"variables>variable"`
}
